
#include "TaskScheduler.h"
#include "SchedulingAlgorithm_Greed.h"
#include "Common/Strings.h"
#include "../DeviceAnalyzer/CPUAnalyzer.h"
#include "Runtime.Low/Utils/UtilManager.h"


using namespace ttg;
using namespace ttg::threads;
using namespace ttg::services;
using namespace ttg::utils;

//---------------------
//--- TaskScheduler ---
//---------------------

TaskScheduler *TaskScheduler::ref = NULL;

void TaskScheduler::startUnSafe(std::vector<Service *> &deps, const char *params)
{
	settings = TaskSchedulerSettings::deSerialize(params);
	//Creating filter.
	filter = new ParameterSet("TaskScheduler", UtilManager::getRef()->getInternalSets()->getServices());
	//Creating device states.
	ttg_internal::devices::RefIniter::check();
	const std::vector<ttg::devices::Device *> &en = ttg::devices::Device::getAllDevices();
	for (size_t i = 0; i < en.size(); i++)
		device_states.push_back(new ttg_internal::services::DeviceState(en[i], filter));
	//Detecting worker count.
	if (settings.getWorkerCount() <= 0)
		settings.setWorkerCount((int)CPUAnalyzer::getRef()->getCoreCount());
	//Creating pool and scheduling algorithm.
	pool = new ThreadPool((size_t)settings.getWorkerCount());
	//pool = new ThreadPool((size_t)1);
	pool->onIdle() += structures::make_delegate(this, onIdlePerformer);
	algorithm = new ttg_internal::services::SchedulingAlgorithm_Greed(device_states);
}

void TaskScheduler::stopUnSafe()
{
	SAFE_DELETE(pool);
	SAFE_DELETE(algorithm);
	SAFE_DELETE_CONTENT(&device_states);
	SAFE_DELETE(filter);
}

void TaskScheduler::sendTasks(size_t task_count)
{
	//Preparing.
	std::vector<threads::Task *> tasks;
	Task *t;
	while (task_count-- > 0 && (t = algorithm->getTask()) != NULL)
		tasks.push_back(t);
	//Sending.
	if (tasks.size() != 0)
	{
		pool->addTasks(structures::StlEnumerator<threads::Task *, std::vector<threads::Task *>::iterator>
								(tasks.begin(), tasks.end()));
	}
}

Task *TaskScheduler::onIdlePerformer(TaskScheduler *scheduler, size_t idle_performers)
{
	Task *res = NULL;
	scheduler->locker.enter();
	res = scheduler->algorithm->getTask();
	scheduler->locker.leave();
	return res;
}

TaskScheduler::TaskScheduler()
	:Service("TaskScheduler", "DeviceAnalyzer UtilManager", false)
{
	pool = NULL;
	makeRegistration();
}

void TaskScheduler::split(std::vector<Task *> &tasks,
						  std::vector<Task *> &root_tasks,
						  std::vector<Task *> &child_tasks)
{
	root_tasks.reserve(tasks.size() + root_tasks.size());
	for (size_t i = 0; i < tasks.size(); i++)
		root_tasks.push_back(tasks[i]);
	tasks.clear();
}

void TaskScheduler::addTasks(ttg::structures::Enumerator<ttg::threads::Task *> &en)
{
	locker.enter();
	//Registering tasks.
	algorithm->addTasks(en);
	//Sending tasks to pool.
	sendTasks(pool->getIdlePerformerCount());
	locker.leave();
}

void TaskScheduler::addTasks(ttg::structures::Enumerator<WiseTask *> &en)
{
	locker.enter();
	//Registering tasks.
	algorithm->addTasks(en);
	//Sending tasks to pool.
	sendTasks(pool->getIdlePerformerCount());
	locker.leave();
}

TaskScheduler::~TaskScheduler()
{
	stop();
}
